#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
MySQL挂机系统管理器
负责角色挂机的管理和收益计算（基于MySQL数据库）
"""

import logging
from datetime import datetime, timedelta
from typing import List, Dict, Any, Optional, Tuple
from database import db_manager, IdleLocation, IdleRecord, Character, GAME_CONFIG
from database.models import CharacterStatus

class MySQLIdleManager:
    """
    基于MySQL的挂机系统管理器
    """
    
    def __init__(self):
        """
        初始化挂机管理器
        """
        self.logger = logging.getLogger(__name__)
        self.max_idle_hours = GAME_CONFIG['max_idle_hours']  # 最大挂机时长
        
        # 测试数据库连接
        if not db_manager.test_connection():
            raise Exception("数据库连接失败")
    
    def get_idle_locations(self) -> List[Dict[str, Any]]:
        """
        获取所有挂机地点
        
        Returns:
            地点列表
        """
        try:
            query = """
                SELECT id, name, description, min_level, max_level, base_exp_rate
                FROM idle_locations 
                WHERE is_active = 1
                ORDER BY min_level
            """
            
            locations = db_manager.execute_query(query)
            
            result = []
            for location in locations:
                result.append({
                    'id': location['id'],
                    'name': location['name'],
                    'description': location['description'],
                    'min_level': location['min_level'],
                    'max_level': location['max_level'],
                    'base_exp_rate': location['base_exp_rate']
                })
            
            return result
            
        except Exception as e:
            self.logger.error(f"获取挂机地点失败: {e}")
            return []
    
    def get_available_locations(self, character: Character) -> List[Dict[str, Any]]:
        """
        获取角色可用的挂机地点
        
        Args:
            character: 角色对象
            
        Returns:
            可用地点列表
        """
        try:
            query = """
                SELECT * FROM idle_locations 
                WHERE is_active = 1 AND min_level <= %s AND max_level >= %s
                ORDER BY min_level
            """
            
            locations = db_manager.execute_query(query, (character.level, character.level))
            
            result = []
            for location in locations:
                # 计算预期收益
                exp_rate = self._calculate_exp_rate(character, location)
                gold_rate = self._calculate_gold_rate(character, location)
                
                result.append({
                    'location_id': location['id'],
                    'name': location['name'],
                    'description': location['description'],
                    'min_level': location['min_level'],
                    'max_level': location['max_level'],
                    'available': True,
                    'reason': '',
                    'exp_rate': exp_rate,
                    'gold_rate': gold_rate
                })
            
            return result
            
        except Exception as e:
            self.logger.error(f"获取可用地点失败: {e}")
            return []
    
    def start_idle(self, character_id: int, location_id: int = 1) -> Tuple[bool, str]:
        """
        开始挂机 - 不再区分挂机地点，使用默认地点
        
        Args:
            character_id: 角色ID
            location_id: 挂机地点ID (为了兼容性保留，但始终使用默认值)
            
        Returns:
            (成功标志, 消息)
        """
        try:
            # 获取角色对象
            character = self._get_character_for_settlement(character_id)
            if not character:
                return False, "角色不存在"
            
            # 检查角色状态
            if character.status == CharacterStatus.IDLE:
                return False, "角色已经在挂机中"
            
            if character.status == CharacterStatus.BATTLE:
                return False, "角色正在战斗中，无法挂机"
            
            # 使用默认地点ID=1
            location_id = 1
            location = self._get_location_by_id(location_id)
            if not location:
                # 如果默认地点不存在，创建一个
                self._create_default_location()
                location = {'id': 1, 'name': '默认挂机地点'}
            
            # 结束当前挂机记录
            self._end_current_idle(character_id)
            
            # 创建新的挂机记录
            insert_query = """
                INSERT INTO idle_records (character_id, location_id, start_time, status)
                VALUES (%s, %s, %s, %s)
            """
            
            record_id = db_manager.execute_insert(insert_query, (
                character_id, location_id, datetime.now(), 'active'
            ))
            
            # 更新角色状态
            self._update_character_status(character_id, CharacterStatus.IDLE)
            
            self.logger.info(f"角色 {character.name} 开始挂机")
            return True, "开始挂机"
            
        except Exception as e:
            self.logger.error(f"开始挂机失败: {e}")
            return False, f"开始挂机失败: {str(e)}"
    
    def stop_idle(self, character_id: int) -> Tuple[bool, str, Dict[str, int]]:
        """
        停止挂机并结算收益 - 现在只收集收益，不停止挂机
        
        Args:
            character_id: 角色ID
            
        Returns:
            (成功标志, 消息, 收益字典)
        """
        try:
            # 获取角色对象
            character = self._get_character_for_settlement(character_id)
            if not character:
                return False, "角色不存在", {}
            
            # 获取当前挂机记录
            current_record = self._get_current_idle_record(character_id)
            if not current_record:
                return False, "角色当前未在挂机", {}
            
            # 计算收益
            rewards = self._calculate_idle_rewards(character, current_record)
            
            # 如果没有收益，直接返回
            if rewards['exp'] <= 0 and rewards['gold'] <= 0:
                return False, "没有可收集的收益", {}
            
            # 结束当前挂机记录
            self._end_current_idle(character_id, rewards)
            
            # 应用收益到角色
            self._apply_rewards_to_character(character, rewards)
            
            # 创建新的挂机记录（继续挂机）
            insert_query = """
                INSERT INTO idle_records (character_id, location_id, start_time, status)
                VALUES (%s, %s, %s, %s)
            """
            
            db_manager.execute_insert(insert_query, (
                character_id, current_record['location_id'], datetime.now(), 'active'
            ))
            
            self.logger.info(f"角色 {character.name} 收集挂机收益，获得经验 {rewards['exp']}，金币 {rewards['gold']}")
            return True, f"收集挂机收益成功", rewards
            
        except Exception as e:
            self.logger.error(f"停止挂机失败: {e}")
            return False, f"停止挂机失败: {str(e)}", {}
    
    def get_idle_status(self, character_id: int) -> Dict[str, Any]:
        """
        获取角色挂机状态
        
        Args:
            character_id: 角色ID
            
        Returns:
            挂机状态信息
        """
        try:
            current_record = self._get_current_idle_record(character_id)
            if not current_record:
                return {
                    'is_idle': False,
                    'location': None,
                    'start_time': None,
                    'duration_hours': 0,
                    'current_rewards': {'exp': 0, 'gold': 0},
                    'max_duration_reached': False
                }
            
            # 获取角色对象用于计算收益
            character = self._get_character_for_settlement(character_id)
            if not character:
                return {
                    'is_idle': False,
                    'location': None,
                    'start_time': None,
                    'duration_hours': 0,
                    'current_rewards': {'exp': 0, 'gold': 0},
                    'max_duration_reached': False
                }
            
            # 计算当前收益
            current_rewards = self._calculate_idle_rewards(character, current_record)
            
            # 计算挂机时长，限制在最大时长内
            duration = datetime.now() - current_record['start_time']
            actual_duration_hours = duration.total_seconds() / 3600
            duration_hours = min(actual_duration_hours, self.max_idle_hours)
            
            # 检查是否达到最大时长
            max_duration_reached = actual_duration_hours >= self.max_idle_hours
            
            # 获取地点信息
            location = self._get_location_by_id(current_record['location_id'])
            
            return {
                'is_idle': True,
                'location': location['name'] if location else '未知地点',
                'location_id': current_record['location_id'],
                'start_time': current_record['start_time'],
                'duration_hours': duration_hours,
                'current_rewards': current_rewards,
                'max_duration_reached': max_duration_reached
            }
            
        except Exception as e:
            self.logger.error(f"获取挂机状态失败: {e}")
            return {
                'is_idle': False,
                'location': None,
                'start_time': None,
                'duration_hours': 0,
                'current_rewards': {'exp': 0, 'gold': 0},
                'max_duration_reached': False
            }
    
    def auto_settle_expired_idle(self):
        """
        自动结算超时的挂机记录
        """
        try:
            # 查找超时的挂机记录
            cutoff_time = datetime.now() - timedelta(hours=self.max_idle_hours)
            
            query = """
                SELECT ir.*, c.id as char_id, c.name as char_name
                FROM idle_records ir
                JOIN characters c ON ir.character_id = c.id
                WHERE ir.status = 'active' AND ir.start_time <= %s
            """
            
            expired_records = db_manager.execute_query(query, (cutoff_time,))
            
            for record in expired_records:
                try:
                    # 创建临时角色对象用于计算收益
                    character = self._get_character_for_settlement(record['char_id'])
                    if not character:
                        continue
                    
                    # 计算最大时长的收益
                    max_duration_record = record.copy()
                    max_duration_record['end_time'] = record['start_time'] + timedelta(hours=self.max_idle_hours)
                    
                    rewards = self._calculate_idle_rewards(character, max_duration_record)
                    
                    # 结束挂机记录
                    self._end_current_idle(record['char_id'], rewards)
                    
                    # 应用收益到角色
                    self._apply_rewards_to_character(character, rewards)
                    
                    # 开始新的挂机记录（继续在同一地点挂机）
                    new_start_time = record['start_time'] + timedelta(hours=self.max_idle_hours)
                    insert_query = """
                        INSERT INTO idle_records (character_id, location_id, start_time, status)
                    VALUES (%s, %s, %s, %s)
                """
                    
                    db_manager.execute_insert(insert_query, (
                    record['char_id'], record['location_id'], new_start_time, 'active'
                ))
                    
                    self.logger.info(f"自动结算角色 {record['char_name']} 的挂机收益")
                    
                except Exception as e:
                    self.logger.error(f"处理过期挂机记录失败: {e}")
                    continue
            
            if expired_records:
                self.logger.info(f"自动结算了 {len(expired_records)} 个过期挂机记录")
                
        except Exception as e:
            self.logger.error(f"自动结算过期挂机失败: {e}")
    
    def _get_current_idle_record(self, char_id: int) -> Optional[Dict[str, Any]]:
        """
        获取角色当前的挂机记录
        
        Args:
            char_id: 角色ID
            
        Returns:
            挂机记录或None
        """
        try:
            query = """
                SELECT * FROM idle_records 
                WHERE character_id = %s AND status = 'active'
                ORDER BY start_time DESC LIMIT 1
            """
            
            result = db_manager.execute_query(query, (char_id,))
            return result[0] if result else None
            
        except Exception as e:
            self.logger.error(f"获取挂机记录失败: {e}")
            return None
    
    def _end_current_idle(self, char_id: int, rewards: Optional[Dict[str, int]] = None):
        """
        结束当前挂机记录
        
        Args:
            char_id: 角色ID
            rewards: 收益字典
        """
        try:
            end_time = datetime.now()
            exp_gained = rewards['exp'] if rewards else 0
            gold_gained = rewards['gold'] if rewards else 0
            
            update_query = """
                UPDATE idle_records 
                SET end_time = %s, exp_gained = %s, status = 'completed'
                WHERE character_id = %s AND status = 'active'
            """
            
            db_manager.execute_update(update_query, (
                end_time, exp_gained, char_id
            ))
            
        except Exception as e:
            self.logger.error(f"结束挂机记录失败: {e}")
    
    def _calculate_idle_rewards(self, character: Character, record: Dict[str, Any]) -> Dict[str, int]:
        """
        计算挂机收益
        
        Args:
            character: 角色对象
            record: 挂机记录
            
        Returns:
            收益字典
        """
        try:
            # 计算挂机时长
            start_time = record.get('start_time')
            
            if not start_time:
                return {'exp': 0, 'gold': 0}
            
            # 对于活跃的挂机记录，end_time为None，使用当前时间
            end_time = record.get('end_time')
            if end_time is None:
                end_time = datetime.now()
            
            duration = end_time - start_time
            duration_hours = min(duration.total_seconds() / 3600, self.max_idle_hours)
            
            # 获取地点信息 (为了兼容性保留，但不再使用地点特性)
            location = self._get_location_by_id(record['location_id'])
            
            # 计算经验收益 - 只基于角色等级
            exp_rate = self._calculate_exp_rate(character)
            exp_gained = int(exp_rate * duration_hours)
            
            # 检查是否超过最大经验积累值 (每个角色最多积累等级*100的经验)
            max_exp_accumulation = character.level * 100
            current_accumulated_exp = self._get_accumulated_exp(character.char_id)
            
            if current_accumulated_exp >= max_exp_accumulation:
                # 已达到最大积累值，不再累计
                exp_gained = 0
            elif current_accumulated_exp + exp_gained > max_exp_accumulation:
                # 部分累计到最大值
                exp_gained = max_exp_accumulation - current_accumulated_exp
            
            # 计算金币收益 - 简化为基于等级的固定值
            gold_rate = 10 + character.level * 2  # 基础10金币/小时，每级+2
            gold_gained = int(gold_rate * duration_hours)
            
            return {
                'exp': exp_gained,
                'gold': gold_gained
            }
            
        except Exception as e:
            self.logger.error(f"计算挂机收益失败: {e}")
            return {'exp': 0, 'gold': 0}
    
    def _calculate_exp_rate(self, character: Character, location: Dict[str, Any] = None) -> float:
        """
        计算经验获取速率 - 现在只基于角色等级计算，不再考虑地点
        
        Args:
            character: 角色对象
            location: 地点信息（为了兼容性保留，但不再使用）
            
        Returns:
            每小时经验
        """
        from src.character.experience_system import exp_system
        
        # 使用新的经验系统计算挂机经验速率，不再使用地点倍率
        exp_rate = exp_system.calculate_idle_exp_rate(character.level, 1.0)
        
        return exp_rate
    
    def _calculate_gold_rate(self, character: Character, location: Dict[str, Any] = None) -> float:
        """
        计算金币获取速率 - 现在只基于角色等级计算
        
        Args:
            character: 角色对象
            location: 地点信息（为了兼容性保留，但不再使用）
            
        Returns:
            每小时金币
        """
        # 简化为基于等级的固定值
        base_rate = 10  # 基础每小时10金币
        level_bonus = character.level * 2  # 每级+2金币
        return base_rate + level_bonus
        
    def _get_accumulated_exp(self, character_id: int) -> int:
        """
        获取角色当前累计的未领取经验
        
        Args:
            character_id: 角色ID
            
        Returns:
            累计经验值
        """
        try:
            # 查询已完成但未领取的挂机记录的经验总和
            query = """
                SELECT COALESCE(SUM(exp_gained), 0) as total_exp
                FROM idle_records 
                WHERE character_id = %s AND status = 'completed' AND exp_gained > 0
            """
            
            result = db_manager.execute_query(query, (character_id,))
            return result[0]['total_exp'] if result else 0
            
        except Exception as e:
            self.logger.error(f"获取累计经验失败: {e}")
            return 0
            
    def _create_default_location(self):
        """
        创建默认挂机地点
        """
        try:
            # 检查默认地点是否已存在
            query = "SELECT * FROM idle_locations WHERE id = 1"
            result = db_manager.execute_query(query)
            
            if not result:
                # 创建默认地点
                insert_query = """
                    INSERT INTO idle_locations (id, name, description, base_exp_rate, base_gold_rate, min_level, max_level, status)
                    VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
                """
                
                db_manager.execute_insert(insert_query, (
                    1, "默认挂机地点", "所有角色的默认挂机地点", 100, 10, 1, 100, 'active'
                ))
                
                self.logger.info("创建了默认挂机地点")
                
        except Exception as e:
            self.logger.error(f"创建默认挂机地点失败: {e}")
    
    def _get_location_by_id(self, location_id: int) -> Optional[Dict[str, Any]]:
        """
        根据ID获取地点信息
        
        Args:
            location_id: 地点ID
            
        Returns:
            地点信息或None
        """
        try:
            query = "SELECT * FROM idle_locations WHERE id = %s"
            result = db_manager.execute_query(query, (location_id,))
            return result[0] if result else None
            
        except Exception as e:
            self.logger.error(f"获取地点信息失败: {e}")
            return None
    
    def _update_character_status(self, char_id: int, status: CharacterStatus):
        """
        更新角色状态
        
        Args:
            char_id: 角色ID
            status: 新状态
        """
        try:
            update_query = """
                UPDATE characters 
                SET status = %s, last_active = %s
                WHERE id = %s
            """
            
            db_manager.execute_update(update_query, (
                status.value, datetime.now(), char_id
            ))
            
        except Exception as e:
            self.logger.error(f"更新角色状态失败: {e}")
    
    def _apply_rewards_to_character(self, character: Character, rewards: Dict[str, int]):
        """
        将收益应用到角色
        
        Args:
            character: 角色对象
            rewards: 收益字典
        """
        try:
            old_level = character.level
            
            # 使用新的经验系统添加经验和处理升级
            levels_gained = character.add_exp(rewards['exp'])
            
            # 更新数据库
            update_query = """
                UPDATE characters 
                SET level = %s, exp = %s, hp = %s, mp = %s, attack = %s, defense = %s, speed = %s, last_active = %s
                WHERE id = %s
            """
            
            db_manager.execute_update(update_query, (
                character.level, character.exp, character.hp, character.mp,
                character.attack, character.defense, character.speed,
                datetime.now(), character.char_id
            ))
            
            # 记录升级信息
            if levels_gained:
                self.logger.info(f"角色 {character.name} 从 {old_level} 级升级到 {character.level} 级，升级路径: {levels_gained}")
            
        except Exception as e:
            self.logger.error(f"应用收益失败: {e}")
    
    def _get_character_for_settlement(self, char_id: int) -> Optional[Character]:
        """
        获取用于结算的角色对象
        
        Args:
            char_id: 角色ID
            
        Returns:
            角色对象或None
        """
        try:
            query = "SELECT * FROM characters WHERE id = %s"
            result = db_manager.execute_query(query, (char_id,))
            
            if result:
                row = result[0]
                from database.models import Character as DBCharacter, CharacterClass
                
                character = DBCharacter(
                    char_id=row['id'],
                    account_id=row['account_id'],
                    name=row['name'],
                    char_class=CharacterClass(row['character_class']),
                    level=row['level'],
                    exp=row['exp'],
                    hp=row['hp'],
                    mp=row['mp'],
                    attack=row['attack'],
                    defense=row['defense'],
                    speed=row['speed'],
                    status=CharacterStatus(row['status']),
                    created_at=row['created_at'],
                    last_active=row['last_active']
                )
                
                return character
            
            return None
            
        except Exception as e:
            self.logger.error(f"获取角色失败: {e}")
            return None
    
    def get_idle_history(self, character: Character, limit: int = 10) -> List[Dict[str, Any]]:
        """
        获取角色挂机历史
        
        Args:
            character: 角色对象
            limit: 返回记录数量限制
            
        Returns:
            挂机历史列表
        """
        try:
            query = """
                SELECT ir.*, il.name as location_name
                FROM idle_records ir
                JOIN idle_locations il ON ir.location_id = il.id
                WHERE ir.character_id = %s AND ir.status = 'completed'
                ORDER BY ir.start_time DESC
                LIMIT %s
            """
            
            result = db_manager.execute_query(query, (character.char_id, limit))
            
            history = []
            for record in result:
                duration = record['end_time'] - record['start_time']
                duration_hours = duration.total_seconds() / 3600
                
                history.append({
                    'location_name': record['location_name'],
                    'start_time': record['start_time'],
                    'end_time': record['end_time'],
                    'duration_hours': round(duration_hours, 2),
                    'exp_gained': record['exp_gained'],
                    'gold_gained': record['gold_gained']
                })
            
            return history
            
        except Exception as e:
            self.logger.error(f"获取挂机历史失败: {e}")
            return []
    
    def collect_idle_rewards(self, character_id: int) -> int:
        """
        收集挂机收益但不停止挂机 - 此方法已被stop_idle替代
        
        Args:
            character_id: 角色ID
            
        Returns:
            获得的经验值
        """
        # 此方法已被stop_idle替代，保留此方法是为了兼容性
        success, _, rewards = self.stop_idle(character_id)
        if success:
            return rewards.get('exp', 0)
        return 0